package org.epanetgrid.otimizacao.ag;
import org.jheuristics.ga.multiObjective.DefaultMultiObjetiveFitness;
import org.jheuristics.ga.multiObjective.MultiObjectiveFitness;

/**
 * Classe com implementa��o default do fitness que � atribuido aos invid�duos em otimiza��es multiobjetivo
 * @author Thiago Emmanuel Pereira da Cunha Silva, thiagoepdc@ourgrid.org, Oct 31, 2005
 * @author Marcell Manfrin, marcell@ourgrid.org, Oct 31, 2005
 */
public class SPMultiObjectiveFitness extends DefaultMultiObjetiveFitness implements SimpleFitness {
	private int intervaloDeErro;
	private int severidade;
	private int tipoDeMutacao;

	/**
	 * 
	 * @param fitness
	 * @param erro Intervalo onde ocorreu o primeiro erro, -1 caso n�o exista erro
	 * @param severidade Severidade do alarme ocorrido, -2 se n�o tem alarme
	 * @param tipoDeMutacao Tipo de muta��o a ser efetuado para "corrigir" o alarme
	 */
	public SPMultiObjectiveFitness(Comparable[] fitness, int erro, int severidade, int tipoDeMutacao) {
		super(fitness);
		this.intervaloDeErro = erro;
		this.severidade = severidade;
		this.tipoDeMutacao = tipoDeMutacao;
	}

	/*
	 * (non-Javadoc)
	 * @see org.smartpumping.otimizacao.ag.SimpleFitness#getIntervaloDeErro()
	 */
	public int getIntervaloDeErro( ) {
		return this.intervaloDeErro;
	}

	/*
	 * (non-Javadoc)
	 * @see org.smartpumping.otimizacao.ag.SimpleFitness#getSeveridade()
	 */
	public int getSeveridade( ) {
		return this.severidade;
	}

	/*
	 * (non-Javadoc)
	 * @see org.smartpumping.otimizacao.ag.SimpleFitness#getTipoDeMutacao()
	 */
	public int getTipoDeMutacao( ) {
		return this.tipoDeMutacao;
	}

	/*
	 * (non-Javadoc)
	 * @see org.jheuristics.ga.multiObjective.MultiObjectiveFitness#relatesTo(java.lang.Object)
	 */
	public int relatesTo(Object o) {
		if (!(o instanceof MultiObjectiveFitness)) {
			if (null == o) {
				throw new NullPointerException();
			}
			throw new ClassCastException();
		}
		Comparable[] fitness = getObjectives();
		Comparable[] otherFit = ((MultiObjectiveFitness) o).getObjectives();
		if (null == otherFit) {
			throw new NullPointerException();
		}
		if (otherFit.length != fitness.length) {
			throw new IllegalArgumentException();
		}

		int firstDominateSecond = 0;
		int secondDominateFirst = 0;
		for (int i = 0; i < fitness.length; i++) {
			int result = compare(fitness[i], otherFit[i]);
			if (result > 0) {
				// fitness[i] worst than otherFit[i]
				secondDominateFirst = 1;
			} else {
				if (result < 0) {
					// fitness[i] best than otherFit[i]
					firstDominateSecond = 1;
				}
			}
		}
		return firstDominateSecond - secondDominateFirst;
	}

	/**
	 *
	 * @param o
	 * @return retorno equivalemte a compara��o de intervalo de erro, em caso de empare, compara pela severidade, caso contrario, ver super. 
	 * @see java.lang.Comparable#compareTo(java.lang.Object)
	 */
	public int compareTo(Object o) {
		if (!(o instanceof SimpleFitness)  && !(o instanceof MultiObjectiveFitness)) {
			if (null == o) {
				throw new NullPointerException();
			}
			throw new ClassCastException();
		}
		SimpleFitness otherFit = (SimpleFitness) o;

        int result = comparaIntervalo(intervaloDeErro, otherFit.getIntervaloDeErro());
		if (result == 0) {
			result = comparaSeveridade(severidade, otherFit.getSeveridade());
			if (result == 0) {
				return super.compareTo(otherFit);
			}
		}
		return result;
	}

    /**
     *	Faz comparacao entre duas severidades
     *
     * @param a
     * @param b
     * @return retorna < que 0 caso "a" seja maior, > 0 caso contr�rio 
     */
    private int comparaSeveridade(int a, int b) {
    	if (a == -1 || b == -1) {
    		if (a < b) {
    			return 1;
    		}
    		if (b < a) {
    			return -1;
    		}
    	}
		return b - a;
	}

    /**
     *
     * Faz compara��o dos intervalos de erro
     *
     * @param a
     * @param b
     * @return retorna < que 0 caso "a" seja maior, > 0 caso contr�rio 
     */
    private static int comparaIntervalo(int a, int b) {
        if (a == -1 || b == -1) {
            // 1st n�o tem erro e 2nd tem 
            if (a < b) {
                return 1;
            }
            // 1st tem erro e 2nd n�o
            if (a > b) {
                return -1;
            }
        } else {
            // ambos contem erro, mas a � antes de b
            if (a < b) {
                return -1;
            }
            // ambos contem erro, mas a � depois de b
            if (a > b) {
                return 1;
            }
        }
        // quando s�o iguais.
        return 0;
    }

}
